/**
* Copyright (C) 2014-2017 Philip Helger (www.helger.com)
* philip[at]helger[dot]com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.helger.erechnung.erb.ws200;
import java.net.URL;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.WebServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.collection.CollectionHelper;
import com.helger.commons.system.SystemProperties;
import com.helger.commons.url.URLHelper;
import com.helger.commons.ws.WSClientConfig;
import com.helger.erechnung.erb.ws.AbstractWSSender;
import com.helger.erechnung.erb.ws.SOAPAddWSSEHeaderHandler;
import com.helger.xml.serialize.write.XMLWriter;
import com.helger.xml.serialize.write.XMLWriterSettings;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.DeliverInvoiceFaultInvoice;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.DeliveryEmbeddedAttachmentType;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.DeliveryErrorDetailType;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.DeliveryErrorType;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.DeliveryInvoiceType;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.DeliveryResponseType;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.DeliverySettingsType;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.DeliveryType;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.WSInvoiceDeliveryPort;
import at.gv.brz.eproc.erb.ws.invoicedelivery._201306.WSInvoiceDeliveryService;
/**
* A wrapper for invoking the Webservice 2.0 for ER>B - E-Rechnung an den
* Bund. The technical details can be found at
*
* @see "https://www.erb.gv.at/erb?p=info_channel_ws&tab=ws20"
* @author Philip Helger
*/
@NotThreadSafe
public class WS200Sender extends AbstractWSSender <WS200Sender>
{
public static final URL ENDPOINT_URL_PRODUCTION = URLHelper.getAsURL ("https://txm.portal.at/at.gv.bmf.erb/V2");
public static final URL ENDPOINT_URL_TEST = URLHelper.getAsURL ("https://txm.portal.at/at.gv.bmf.erb.test/V2");
// Logger to use
private static final Logger s_aLogger = LoggerFactory.getLogger (WS200Sender.class);
public WS200Sender (@Nonnull @Nonempty final String sWebserviceUsername,
@Nonnull @Nonempty final String sWebservicePassword)
{
super (sWebserviceUsername, sWebservicePassword);
}
@Nonnull
private static DeliveryResponseType _createError (@Nonnull final String sField, @Nonnull final String sMessage)
{
return _createError (sField, CollectionHelper.newList (sMessage));
}
@Nonnull
private static DeliveryResponseType _createError (@Nonnull final String sField,
@Nonnull final List <String> aMessages)
{
final DeliveryResponseType ret = new DeliveryResponseType ();
final DeliveryErrorType aError = new DeliveryErrorType ();
for (final String sMessage : aMessages)
{
final DeliveryErrorDetailType aDetail = new DeliveryErrorDetailType ();
aDetail.setField (sField);
aDetail.setMessage (sMessage);
aError.getErrorDetail ().add (aDetail);
}
ret.setError (aError);
return ret;
}
/**
* This is the main sending routine. It can be invoked multiple times with
* different invoices.
*
* @param aOriginalInvoice
* The original invoice in an XML representation. May not be
* <code>null</code>. It may be in any of the formats supported by
* ER>B (ebInterface 3.0, 3.02, 4.0, 4.1 or UBL 2.0, 2.1).
* @param aAttachments
* An optional list of attachments to this invoice. If the list is non-
* <code>null</code> it must contain only non-<code>null</code>
* elements.
* @param aSettings
* The settings element as specified by the ER>B Webservice 1.2.
* Within this settings element e.g. the test-flag can be set. May not
* be <code>null</code>.
* @return A non-<code>null</code> upload status as returned by the ER>B
* Webservice. In case of an internal error, a corresponding error
* structure is created.
*/
@Nonnull
public DeliveryResponseType deliverInvoice (@Nonnull final Node aOriginalInvoice,
@Nullable final List <DeliveryEmbeddedAttachmentType> aAttachments,
@Nonnull final DeliverySettingsType aSettings)
{
ValueEnforcer.notNull (aOriginalInvoice, "OriginalInvoice");
ValueEnforcer.notNull (aSettings, "Settings");
// Some debug output
SystemProperties.setPropertyValue ("com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", isDebugMode ());
SystemProperties.setPropertyValue ("com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump",
isDebugMode ());
// Convert XML node to a String
final XMLWriterSettings aXWS = new XMLWriterSettings ().setCharset (getInvoiceEncoding ());
final String sInvoiceString = XMLWriter.getNodeAsString (aOriginalInvoice, aXWS);
if (sInvoiceString == null)
{
s_aLogger.error ("Failed to serialize the specified XML document to a String!");
return _createError ("document", "Failed to serialize the specified XML document to a String!");
}
// Prepare document
final DeliveryType aDelivery = new DeliveryType ();
// Main invoice
final DeliveryInvoiceType aInvoice = new DeliveryInvoiceType ();
aInvoice.setValue (sInvoiceString.getBytes (getInvoiceEncoding ()));
aInvoice.setEncoding (getInvoiceEncoding ().name ());
aDelivery.setInvoice (aInvoice);
// Embedded attachments
aDelivery.setEmbeddedAttachment (aAttachments);
// ER>B does not support external attachments!
// Settings
aDelivery.setSettings (aSettings);
try
{
final WSClientConfig aWSClientConfig = new WSClientConfig (isTestVersion () ? ENDPOINT_URL_TEST
: ENDPOINT_URL_PRODUCTION);
if (isTrustAllCertificates ())
{
// Maybe required to trust txm.portal.at depending on the installed OS
// root certificates.
aWSClientConfig.setSSLSocketFactoryTrustAll ();
}
if (isTrustAllHostnames ())
aWSClientConfig.setHostnameVerifierTrustAll ();
// Ensure the WSSE headers are added using our handler
aWSClientConfig.addHandler (new SOAPAddWSSEHeaderHandler (getWebserviceUsername (), getWebservicePassword ()));
// Invoke WS
final WSInvoiceDeliveryService aService = new WSInvoiceDeliveryService ();
final WSInvoiceDeliveryPort aPort = aService.getWSInvoiceDeliveryPort ();
aWSClientConfig.applyWSSettingsToBindingProvider ((BindingProvider) aPort);
// Main sending
final DeliveryResponseType aResult = aPort.deliverInvoice (aDelivery);
return aResult;
}
catch (final DeliverInvoiceFaultInvoice ex)
{
s_aLogger.error ("Error uploading the document to ER>B Webservice 2.0!", ex);
return _createError ("document",
ex.getFaultInfo () != null ? ex.getFaultInfo ().getMessage ()
: CollectionHelper.newList (ex.getMessage ()));
}
catch (final WebServiceException ex)
{
s_aLogger.error ("Error transmitting the document to ER>B Webservice 2.0!", ex);
return _createError ("webservice", ex.getMessage ());
}
catch (final Throwable t)
{
s_aLogger.error ("Generic error invoking ER>B Webservice 2.0", t);
return _createError ("general", t.getMessage ());
}
}
}